#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
设备编码验证器

提供各类设备编码格式的验证功能：
- 台区编码验证
- 电箱编码验证  
- RTU编码验证
- 电表编码验证
"""

from typing import Optional, Dict, Any

from common.logger import create_logger

logger = create_logger(__name__)


class DeviceCodeValidator:
	"""设备编码验证器"""

	# 编码规则常量（与生成器保持一致）
	STATION_PREFIX = "T"
	BOX_PREFIX = "B"
	RTU_PREFIX = "R"
	METER_PREFIX = "M"

	STATION_CODE_LEN = 15
	BOX_CODE_LEN = 19
	RTU_CODE_LEN = 23
	METER_CODE_LEN = 28

	@classmethod
	def validate_station_code(cls, code: str) -> Dict[str, Any]:
		"""
		验证台区编码: T + 9位区县码 + 5位日级流水

		Args:
			code: 台区编码

		Returns:
			验证结果字典，包含 is_valid, error_msg, parsed_info
		"""
		result = {
			"is_valid": False,
			"error_msg": "",
			"parsed_info": {}
		}

		try:
			# 基本格式检查
			if not code:
				result["error_msg"] = "编码不能为空"
				return result

			if len(code) != cls.STATION_CODE_LEN:
				result["error_msg"] = f"编码长度应为{cls.STATION_CODE_LEN}位，实际{len(code)}位"
				return result

			if not code.startswith(cls.STATION_PREFIX):
				result["error_msg"] = f"编码应以{cls.STATION_PREFIX}开头"
				return result

			# 提取组成部分
			area_code = code[1:10]  # 9位区县码
			sequence = code[10:15]  # 5位流水

			# 验证区县码（数字）
			if not area_code.isdigit():
				result["error_msg"] = "区县码部分应为9位数字"
				return result

			# 验证区县码格式（省市区都不能为00）
			province = area_code[:2]
			city = area_code[2:4]
			area = area_code[4:6]

			if province == "00":
				result["error_msg"] = "省级编码不能为00"
				return result

			if city == "00":
				result["error_msg"] = "市级编码不能为00"
				return result

			if area == "00":
				result["error_msg"] = "区县编码不能为00"
				return result

			# 验证流水号（数字）
			if not sequence.isdigit():
				result["error_msg"] = "流水号部分应为5位数字"
				return result

			# 所有验证通过
			result["is_valid"] = True
			result["parsed_info"] = {
				"prefix": cls.STATION_PREFIX,
				"area_code": area_code,
				"province_code": province,
				"city_code": city,
				"area_district_code": area,
				"sequence": int(sequence),
				"date_info": area_code[6:]  # 后3位可能包含日期信息
			}

		except Exception as e:
			logger.exception(f"台区编码验证异常: code={code}")
			result["error_msg"] = f"验证过程异常: {e}"

		return result

	@classmethod
	def validate_box_code(cls, code: str, station_code: Optional[str] = None) -> Dict[str, Any]:
		"""
		验证电箱编码: B + 台区码(去掉T前缀) + 4位流水

		Args:
			code: 电箱编码
			station_code: 对应的台区编码（可选，用于关联验证）

		Returns:
			验证结果字典
		"""
		result = {
			"is_valid": False,
			"error_msg": "",
			"parsed_info": {}
		}

		try:
			# 基本格式检查
			if not code:
				result["error_msg"] = "编码不能为空"
				return result

			if len(code) != cls.BOX_CODE_LEN:
				result["error_msg"] = f"编码长度应为{cls.BOX_CODE_LEN}位，实际{len(code)}位"
				return result

			if not code.startswith(cls.BOX_PREFIX):
				result["error_msg"] = f"编码应以{cls.BOX_PREFIX}开头"
				return result

			# 提取组成部分
			station_part = code[1:15]  # 台区编码部分（去掉T前缀）
			sequence = code[15:19]  # 4位流水

			# 验证台区编码部分
			reconstructed_station_code = cls.STATION_PREFIX + station_part
			station_result = cls.validate_station_code(reconstructed_station_code)
			if not station_result["is_valid"]:
				result["error_msg"] = f"台区编码部分无效: {station_result['error_msg']}"
				return result

			# 验证流水号
			if not sequence.isdigit():
				result["error_msg"] = "流水号部分应为4位数字"
				return result

			sequence_int = int(sequence)
			if sequence_int == 0:
				result["error_msg"] = "流水号不能为0000"
				return result

			# 关联验证（如果提供了台区编码）
			if station_code:
				if reconstructed_station_code != station_code:
					result["error_msg"] = f"电箱编码与台区编码不匹配: {reconstructed_station_code} != {station_code}"
					return result

			# 所有验证通过
			result["is_valid"] = True
			result["parsed_info"] = {
				"prefix": cls.BOX_PREFIX,
				"station_code": reconstructed_station_code,
				"station_part": station_part,
				"sequence": sequence_int,
				"station_info": station_result["parsed_info"]
			}

		except Exception as e:
			logger.exception(f"电箱编码验证异常: code={code}")
			result["error_msg"] = f"验证过程异常: {e}"

		return result

	@classmethod
	def validate_rtu_code(cls, code: str, parent_code: Optional[str] = None, parent_type: Optional[str] = None) -> Dict[
		str, Any]:
		"""
		验证RTU编码
		- 电箱下RTU: R + 电箱码(去掉B前缀) + 3位流水
		- 台区直挂RTU: R + 台区码(去掉T前缀) + 5位流水

		Args:
			code: RTU编码
			parent_code: 父级设备编码（可选）
			parent_type: 父级类型 ("box" 或 "station"，可选）

		Returns:
			验证结果字典
		"""
		result = {
			"is_valid": False,
			"error_msg": "",
			"parsed_info": {}
		}

		try:
			# 基本格式检查
			if not code:
				result["error_msg"] = "编码不能为空"
				return result

			if len(code) != cls.RTU_CODE_LEN:
				result["error_msg"] = f"编码长度应为{cls.RTU_CODE_LEN}位，实际{len(code)}位"
				return result

			if not code.startswith(cls.RTU_PREFIX):
				result["error_msg"] = f"编码应以{cls.RTU_PREFIX}开头"
				return result

			# 判断RTU类型（通过流水号长度）
			# 电箱下RTU: 总长23位，R(1) + 电箱部分(18) + 流水(3) = 22位，实际应该是23位
			# 台区直挂RTU: 总长23位，R(1) + 台区部分(14) + 流水(5) = 20位，实际应该是23位

			# 尝试解析为电箱下RTU（R + 18位电箱部分 + 3位流水）
			if len(code) == cls.RTU_CODE_LEN:
				# 先尝试电箱下RTU模式
				box_part = code[1:19]  # 18位电箱部分
				box_sequence = code[19:22]  # 3位流水
				remaining = code[22:]  # 剩余部分

				if len(box_sequence) == 3 and box_sequence.isdigit() and len(remaining) == 1 and remaining.isdigit():
					# 可能是电箱下RTU，但长度不对，重新计算
					# 实际应该是：R + 电箱码(19位去掉B前缀=18位) + 3位流水 = 22位
					# 但定义是23位，说明有问题
					pass

				# 重新按正确格式解析
				# 假设格式为：R + parent_part + sequence
				# 需要根据parent_type确定分割点

				if parent_type == "box":
					# 电箱下RTU: R + 电箱部分(18位) + 3位流水 = 22位，但总长是23位
					# 重新理解：可能是 R + 电箱码去掉B(18位) + 3位流水，但要保持23位总长
					parent_part = code[1:20]  # 19位
					sequence = code[20:23]  # 3位流水

					if len(sequence) != 3 or not sequence.isdigit():
						result["error_msg"] = "RTU流水号应为3位数字"
						return result

					# 验证电箱部分
					reconstructed_box_code = cls.BOX_PREFIX + parent_part
					if parent_code and reconstructed_box_code != parent_code:
						result["error_msg"] = f"RTU编码与电箱编码不匹配"
						return result

					result["parsed_info"] = {
						"prefix": cls.RTU_PREFIX,
						"parent_type": "box",
						"parent_part": parent_part,
						"sequence": int(sequence),
						"reconstructed_parent_code": reconstructed_box_code
					}

				elif parent_type == "station":
					# 台区直挂RTU: R + 台区部分(14位) + 5位流水 = 20位，但总长是23位
					# 可能格式有误，按实际23位重新分配
					parent_part = code[1:18]  # 17位？这样不对
					# 重新理解：R + 台区码去掉T(14位) + 5位流水 = 20位，总长23位有问题

					# 按照设计文档，应该是：
					# R + 台区码(去掉T前缀，14位) + 5位流水 = 1+14+5 = 20位
					# 但类定义说RTU总长23位，可能有误差，按实际分析

					parent_part = code[1:15]  # 14位台区部分
					sequence = code[15:20]  # 5位流水
					remaining = code[20:]  # 剩余3位

					if len(sequence) != 5 or not sequence.isdigit():
						result["error_msg"] = "台区直挂RTU流水号应为5位数字"
						return result

					# 如果有剩余位，可能格式定义有问题
					if remaining and not remaining.isdigit():
						result["error_msg"] = f"RTU编码格式异常，剩余部分: {remaining}"
						return result

					# 验证台区部分
					reconstructed_station_code = cls.STATION_PREFIX + parent_part
					if parent_code and reconstructed_station_code != parent_code:
						result["error_msg"] = f"RTU编码与台区编码不匹配"
						return result

					result["parsed_info"] = {
						"prefix": cls.RTU_PREFIX,
						"parent_type": "station",
						"parent_part": parent_part,
						"sequence": int(sequence),
						"reconstructed_parent_code": reconstructed_station_code,
						"remaining": remaining
					}

				else:
					# 自动推断类型
					# 尝试作为电箱下RTU解析
					if cls._try_parse_as_box_rtu(code):
						parent_part = code[1:20]
						sequence = code[20:23]
						result["parsed_info"] = {
							"prefix": cls.RTU_PREFIX,
							"parent_type": "box",
							"parent_part": parent_part,
							"sequence": int(sequence),
							"reconstructed_parent_code": cls.BOX_PREFIX + parent_part
						}
					else:
						# 尝试作为台区直挂RTU解析
						parent_part = code[1:15]
						sequence = code[15:20]
						result["parsed_info"] = {
							"prefix": cls.RTU_PREFIX,
							"parent_type": "station",
							"parent_part": parent_part,
							"sequence": int(sequence),
							"reconstructed_parent_code": cls.STATION_PREFIX + parent_part
						}

			result["is_valid"] = True

		except Exception as e:
			logger.exception(f"RTU编码验证异常: code={code}")
			result["error_msg"] = f"验证过程异常: {e}"

		return result

	@classmethod
	def _try_parse_as_box_rtu(cls, code: str) -> bool:
		"""尝试将RTU编码解析为电箱下RTU"""
		try:
			if len(code) != cls.RTU_CODE_LEN:
				return False

			parent_part = code[1:20]  # 19位电箱部分
			sequence = code[20:23]  # 3位流水

			# 检查流水号格式
			if len(sequence) != 3 or not sequence.isdigit():
				return False

			# 检查电箱部分是否合理（重构电箱编码进行验证）
			reconstructed_box_code = cls.BOX_PREFIX + parent_part
			box_result = cls.validate_box_code(reconstructed_box_code)

			return box_result["is_valid"]

		except Exception:
			return False

	@classmethod
	def validate_meter_code(cls, code: str, rtu_code: Optional[str] = None) -> Dict[str, Any]:
		"""
		验证电表编码: M + RTU码(去掉R前缀) + 4位流水

		Args:
			code: 电表编码
			rtu_code: 对应的RTU编码（可选）

		Returns:
			验证结果字典
		"""
		result = {
			"is_valid": False,
			"error_msg": "",
			"parsed_info": {}
		}

		try:
			# 基本格式检查
			if not code:
				result["error_msg"] = "编码不能为空"
				return result

			if len(code) != cls.METER_CODE_LEN:
				result["error_msg"] = f"编码长度应为{cls.METER_CODE_LEN}位，实际{len(code)}位"
				return result

			if not code.startswith(cls.METER_PREFIX):
				result["error_msg"] = f"编码应以{cls.METER_PREFIX}开头"
				return result

			# 提取组成部分
			rtu_part = code[1:24]  # 23位RTU部分（去掉R前缀是22位，但这里是23位总长-M前缀-4位流水=23位）
			# 重新计算：总长28位，M(1位) + RTU部分(22位) + 流水(4位) = 27位，不对
			# 应该是：M(1位) + RTU码去掉R(22位) + 流水(4位) = 27位，但定义是28位

			rtu_part = code[1:24]  # RTU部分：28-1-4=23位
			sequence = code[24:28]  # 4位流水

			# 验证流水号
			if len(sequence) != 4 or not sequence.isdigit():
				result["error_msg"] = "流水号应为4位数字"
				return result

			sequence_int = int(sequence)
			if sequence_int == 0:
				result["error_msg"] = "流水号不能为0000"
				return result

			# 验证RTU部分
			reconstructed_rtu_code = cls.RTU_PREFIX + rtu_part
			if len(reconstructed_rtu_code) != cls.RTU_CODE_LEN:
				result["error_msg"] = f"重构的RTU编码长度不正确: {len(reconstructed_rtu_code)}"
				return result

			# 关联验证
			if rtu_code and reconstructed_rtu_code != rtu_code:
				result["error_msg"] = f"电表编码与RTU编码不匹配: {reconstructed_rtu_code} != {rtu_code}"
				return result

			# 验证重构的RTU编码格式
			rtu_result = cls.validate_rtu_code(reconstructed_rtu_code)
			if not rtu_result["is_valid"]:
				result["error_msg"] = f"RTU编码部分无效: {rtu_result['error_msg']}"
				return result

			# 所有验证通过
			result["is_valid"] = True
			result["parsed_info"] = {
				"prefix": cls.METER_PREFIX,
				"rtu_code": reconstructed_rtu_code,
				"rtu_part": rtu_part,
				"sequence": sequence_int,
				"rtu_info": rtu_result["parsed_info"]
			}

		except Exception as e:
			logger.exception(f"电表编码验证异常: code={code}")
			result["error_msg"] = f"验证过程异常: {e}"

		return result

	@classmethod
	def validate_device_code(cls, code: str, device_type: str) -> Dict[str, Any]:
		"""
		通用设备编码验证

		Args:
			code: 设备编码
			device_type: 设备类型 ("STATION", "BOX", "RTU", "METER")

		Returns:
			验证结果字典
		"""
		device_type = device_type.upper()

		if device_type == "STATION":
			return cls.validate_station_code(code)
		elif device_type == "BOX":
			return cls.validate_box_code(code)
		elif device_type == "RTU":
			return cls.validate_rtu_code(code)
		elif device_type == "METER":
			return cls.validate_meter_code(code)
		else:
			return {
				"is_valid": False,
				"error_msg": f"不支持的设备类型: {device_type}",
				"parsed_info": {}
			}


# 便捷函数
def validate_station_code(code: str) -> Dict[str, Any]:
	"""验证台区编码"""
	return DeviceCodeValidator.validate_station_code(code)


def validate_box_code(code: str, station_code: Optional[str] = None) -> Dict[str, Any]:
	"""验证电箱编码"""
	return DeviceCodeValidator.validate_box_code(code, station_code)


def validate_rtu_code(code: str, parent_code: Optional[str] = None, parent_type: Optional[str] = None) -> Dict[
	str, Any]:
	"""验证RTU编码"""
	return DeviceCodeValidator.validate_rtu_code(code, parent_code, parent_type)


def validate_meter_code(code: str, rtu_code: Optional[str] = None) -> Dict[str, Any]:
	"""验证电表编码"""
	return DeviceCodeValidator.validate_meter_code(code, rtu_code)


def validate_device_code(code: str, device_type: str) -> Dict[str, Any]:
	"""通用设备编码验证"""
	return DeviceCodeValidator.validate_device_code(code, device_type)
